const inquirer = require("inquirer");
const path = require("path");
const fs = require("fs");
const ansiEscapes = require("ansi-escapes"); // 用于输出空行
const MuteStream = require("mute-stream"); // 用于沉默输出流

class JInquirer {
  constructor(options, config) {
    this.options = options; //参数
    this.config = config || {}; //配置
    this.answer = {}; //输出结果容器
    this.tempList = {}; //中间值临时容器变量
  }
  getFileList = (dirPath) => {
    const list = fs.readdirSync(dirPath);
    return ["../(返回上一级)", ...list];
  };
  getFolderList = (dirPath) => {
    const list = fs.readdirSync(dirPath);
    let resList = [];
    list.forEach((item) => {
      const fullPath = path.join(dirPath, item);
      if (fs.statSync(fullPath).isDirectory()) {
        // resList.push(item + "(进入文件夹)");
        // resList.push(item + "(选择文件夹)");
        resList.push(item);
      }
    });
    return ["../(返回上一级)", `选择当前文件夹(${dirPath})`, ...resList];
  };
  clear = (number) => {
    // 清屏
    const emptyLines = ansiEscapes.eraseLines(number); // 根据函数通过 eraseLines 获取空行
    this.output.write(emptyLines); // 输出空行，完成清屏
  };
  async prompt() {
    const options = this.options;
    const ms = new MuteStream(); // 封装沉默输出流
    ms.pipe(process.stdout);
    this.output = ms; // 导入实例
    for (const element of options) {
      const res = await this.run(element);
      this.answer[element.name] = res;
    }
    return this.answer;
  }
  async run(option) {
    if (option.type === "file") {
      //选择文件
      return this.chooseFile(option, option.dirname);
    } else if (option.type === "folder") {
      //选择文件夹
      return this.chooseFolder(option, option.dirname);
    } else if (option.type === "expandList") {
      //选择多级列表
      this.tempList = {};
      await this.chooseExpandList(option, 0, "", option);
      const res = [];
      for (let k in this.tempList) {
        this.tempList[k].map((item) => {
          res.push(k + "/" + item);
        });
      }
      return res;
    } else {
      if (option.notNull) {
        const flag = option.message.slice(-1);
        if (["：", ":"].includes(flag)) {
          option.message = option.message.slice(0, -1) + "(不能为空)" + flag;
        }
      }
      return this.defaultType(option);
    }
  }
  async chooseFile(option, dirPath = "./") {
    option.type = "list";
    option.suffix = "(当前浏览目录：" + dirPath + ")"; //path.join(__dirname,dirPath)
    option.pageSize = fs.readdirSync("./").length + 1;
    option.choices = [...this.getFileList(dirPath)];
    const answer = await inquirer.prompt([option]);
    if (answer[option.name] == "../(返回上一级)") {
      this.clear(2);
      return this.chooseFile(option, path.join(dirPath, "/../"));
    } else {
      const fullPath = path.join(dirPath, answer[option.name]);
      if (!fs.statSync(fullPath).isFile()) {
        this.clear(2);
        return this.chooseFile(option, fullPath);
      } else {
        return path.join(dirPath, answer[option.name]);
      }
    }
  }
  async chooseFolder(option, dirPath = "./") {
    option.type = "list";
    option.suffix = "(当前浏览目录：" + dirPath + ")"; //path.join(__dirname,dirPath)
    option.choices = [...this.getFolderList(dirPath)];
    option.pageSize = Math.min(option.choices.length, 6);
    const answer = await inquirer.prompt([option]);
    if (answer[option.name] == "../(返回上一级)") {
      this.clear(2);
      return this.chooseFolder(option, path.join(dirPath, "/../"));
    } else if (answer[option.name].startsWith("选择当前文件夹(")) {
      return dirPath;
    } else if (answer[option.name].endsWith("(进入文件夹)")) {
      const iPath = answer[option.name].slice(0, -7);
      this.clear(2);
      return this.chooseFolder(option, path.join(dirPath, iPath));
    } else if (answer[option.name].endsWith("(选择文件夹)")) {
      return path.join(dirPath, answer[option.name].slice(0, -7));
    } else {
      this.clear(2);
      return this.chooseFolder(option, path.join(dirPath, answer[option.name]));
    }
  }
  async chooseExpandList(option, deep, pre, originOption) {
    const obj = option.choices;
    let optionTemp = { ...option };
    let isChoose = "";
    let clearLen = 2;
    let index = 0;
    let rowNum = option.rowNum || 3;
    for (let k in this.tempList) {
      this.tempList[k].map((item) => {
        index++;
        isChoose += isChoose ? "、" : "";
        isChoose += k + "/" + item;
        if (index % rowNum == 0) {
          console.log(
            (index === rowNum ? "当前已选择：" : " ".repeat(12)) + isChoose
          );
          clearLen++;
          isChoose = "";
        }
      });
    }
    if (isChoose) {
      console.log(
        (index < rowNum ? "当前已选择：" : " ".repeat(12)) + isChoose
      );
      clearLen++;
    }
    // console.log('当前已选择：',isChoose);
    optionTemp.default = this.tempList[pre] || [];
    optionTemp.type = Array.isArray(obj) ? "checkbox" : "list";
    optionTemp.suffix = Array.isArray(obj)
      ? this.config.checkboxTip || "(请选择)"
      : this.config.listTip || "(请选择)";
    optionTemp.choices = Array.isArray(obj) ? obj : Object.keys(obj);
    optionTemp.pageSize = optionTemp.choices.length + 1;
    if (deep === 0) optionTemp.choices.unshift("完成选择");
    const answer = await inquirer.prompt([optionTemp]);
    this.clear(clearLen);
    if (answer[option.name] !== "完成选择") {
      if (optionTemp.type === "list") {
        if (pre) pre += "/";
        const op = { ...option };
        op.choices = obj[answer[option.name]];
        await this.chooseExpandList(
          op,
          deep + 1,
          pre + answer[option.name],
          originOption
        );
      } else {
        this.tempList[pre] = answer[option.name];
        await this.chooseExpandList(originOption, 0, "", originOption);
      }
    } else {
      if (!option.notConfirm) return;
      const o = {
        type: "confirm",
        name: "exit",
        message: "确认完成选择",
        default: false,
      };
      const answer = await inquirer.prompt([o]);
      this.clear(clearLen);
      if (!answer.exit) {
        await this.chooseExpandList(originOption, 0, "", originOption);
      } else {
        this.clear(1);
      }
    }
  }
  async defaultType(option) {
    const answer = await inquirer.prompt([option]);
    if (option.notNull && answer[option.name] === "") {
      this.clear(2);
      return this.defaultType(option);
    }
    return answer[option.name];
  }
}
module.exports = JInquirer;
